using System;
using System.Collections;
using System.Runtime.CompilerServices;
using Awaiter;
using Minions.Classes;
using Nsb.Classes;
using jQueryApi;

namespace MinionsEdit.Classes
{
    [IgnoreNamespace]
    public static class MiDrop
    {
        private static readonly Dictionary DropOptions = new Dictionary(
            "accept", Minion.DotMinionClassName,
            "over", (Action<jQueryEvent, jQueryUiObject>) DropOverEv,
            "out", (Action<jQueryEvent, jQueryUiObject>) DropOutEv,
            "drop", (Action<jQueryEvent, jQueryUiObject>) DropDropEv,
            "tolerance", "pointer",
            "hoverClass", "DropOver",
            "greedy", true
            );

        private static string _toId;
        //private static string _fromId;
        private static jQueryUiObject _ui;

        public static void MakeDroppable(MinionEdit mm)
        {
            mm.Element.Plugin<Jewl>().Droppable(DropOptions);
        }

        private static void DropOverEv(jQueryEvent e, jQueryUiObject ui)
        {
            jQueryObject el = jQuery.FromElement(e.Target).Closest(Minion.DotMinionClassName);
#if DEBUG
            if (el.Length == 0)
            {
                Inform.Log("DropOver - err1 id={0}:{1}", e.Target.TagName, e.Target.ID);
                Script.Literal("debugger");
                return;
            }
#endif
            MinionEdit mm = MinionEdit.GetMinionFromEl(el);
#if DEBUG
            if (mm == null)
            {
                Inform.Log("DropOver - err2 id={0}:{1}", e.Target.TagName, e.Target.ID);
                Script.Literal("debugger");
                return;
            }
#endif
            ui.e = e;
            MiMask.DropMaskOn(mm, ui);
        }

        private static void DropOutEv(jQueryEvent e, jQueryUiObject ui)
        {
            jQueryObject el = jQuery.FromElement(e.Target).Closest(Minion.DotMinionClassName);
#if DEBUG
            if (el.Length == 0)
            {
                Inform.Log("DropOut err1 id={0}:{1}", e.Target.TagName, e.Target.ID);
                Script.Literal("debugger");
                return;
            }
#endif
            MinionEdit mm = MinionEdit.GetMinionFromEl(el);
#if DEBUG
            if (mm == null)
            {
                Inform.Log("DropOut err2 id={0}:{1}", e.Target.TagName, e.Target.ID);
                Script.Literal("debugger");
                return;
            }
#endif
            ui.draggable.RemoveClass("DropOver");
            ui.e = e;
            MiMask.DropMaskOff(mm, ui);
        }

        private static void DropDropEv(jQueryEvent e, jQueryUiObject ui)
        {
            Inform.Debug("DropDropEv()");
            if (MiUiOp.cancelled)
                return;
            MinionEdit drop = MinionEdit.GetMinionFromEv(e);
            MinionEdit drag = MinionEdit.GetMinionFromEl(ui.draggable);
            _toId = drop.Id;
            //_fromId = drag.Id;
            _ui = ui;

            if (e.AltKey) // AltKey is a sure DropMove
            {
                new Await().AddDx(delegate { DropMove(e); }).Commit();
                return;
            }

            Pos p = (Pos) (object) drop.Element.GetOffset(); // Shift the menu a bit
            p.Top += 7;
            p.Left += 7;

            if (drag.Parent == null || drag.Parent.Id != drop.Id) // If not dropping on it's own parent
            {
                new MiPopChoice(e, p,
                                new Dictionary(
                                    "move as is", (jQueryEventHandler) DropMove,
                                    "move into this", (jQueryEventHandler) DropInsert,
                                    "copy into this", (jQueryEventHandler) DropCopy,
                                    "cancel", (jQueryEventHandler) DropCancel
                                    ))
                    .Css(new Dictionary("width", 160))
                    .SetCancel(DropCancel)
                    ;
                return;
            }
            MiMask.DropMaskOff(drop, _ui);
        }

        private static void DropInsert(jQueryEvent e)
        {
            MinionEdit drag = MinionEdit.GetMinionFromEl(_ui.draggable);
            MinionEdit drop = MinionEdit.GetMinionById(_toId);
            MiMask.DropMaskOff(drop, _ui);
            if (drag != null)
            {
                new MinionPaste(drop).NoOffset().Paste(MiUiOp.Snapshot);
                MiUiOp.TheMinion.Destroy();
            }
        }

        private static void DropCopy(jQueryEvent e)
        {
            MinionEdit drag = MinionEdit.GetMinionFromEl(_ui.draggable);
            MinionEdit drop = MinionEdit.GetMinionById(_toId);
            MiMask.DropMaskOff(drop, _ui);
            if (drag != null)
            {
                new MinionPaste(drop).NoOffset().Paste(MiUiOp.Snapshot);
                MiUiOp.Restore();
            }
        }

        private static void DropMove(jQueryEvent e)
        {
            MinionEdit drop = MinionEdit.GetMinionById(_toId);
            MiMask.DropMaskOff(drop, _ui);
            // It's already moved so nothing is needed to do
        }

        private static void DropCancel(jQueryEvent e)
        {
            MinionEdit drop = MinionEdit.GetMinionById(_toId);
            MiMask.DropMaskOff(drop, _ui);
            MiUiOp.Restore();
        }
    }
}